/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.publisher;

import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.gidoo.cms.RedirectPage;
import org.gidoo.cms.login.GidooCMSAuthenticatedWebSession;
import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.gidoo.cms.GidooCMS;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.data.CMSSection;
import org.gidoo.cms.data.Folder;
import org.gidoo.cms.data.Page;
import org.gidoo.cms.data.Resource;
import org.gidoo.cms.dbconnection.DatabaseConnectionException;
import org.gidoo.cms.dbconnection.Persistance;
import org.gidoo.cms.editor.edit.PreviewPage;
import org.gidoo.cms.view.XSLTTransformFailedException;
import org.gidoo.wickettools.MessageBox;
import org.gidoo.cms.helper.ResourceDownloadLink;
import org.gidoo.wickettools.XHTMLDiff;

/**
 *
 * @author thomas
 */
@AuthorizeInstantiation(GidooCMSAuthenticatedWebSession.ROLE_PUBLISHER)
public class PublisherPage extends WebPage
{
  
  FeedbackPanel feedback;
  
  ListView lsvPublishPages;
  ListView lsvPublishResources;
  
  List<String> pathsForPagesToPublish;
  HashMap<String,Folder> foldersForPagesToPublish;
  
  List<String> pathsForResourcesToPublish;
  HashMap<String,Resource> resourcesToPublish;
  
  GidooCMSAuthenticatedWebSession theSession;
  
  ModalWindow window;
  
  /** Creates a new instance of PublisherPage */
  public PublisherPage()
  {
    add(HeaderContributor.forCss(AdminPage.CSS_ADMIN));
    
    theSession = (GidooCMSAuthenticatedWebSession) this.getSession();
    
    feedback = new FeedbackPanel("feedbackPanel");
    feedback.setOutputMarkupId(true);
    add(feedback);
    
    window = new ModalWindow("window");
    add(window);
    
    add(new Label("lblTitle", new ResourceModel("publisherPage")));
    add(new Link("lnkLogout")
    {
      public void onClick()
      {
        theSession.signOut();
        this.setResponsePage(RedirectPage.class);
      }
    });
    
    add(new Link("lnkRefresh") {
      @Override
      public void onClick()
      {
        setResponsePage(PublisherPage.class);
      }
    });
    
    
    List<CMSSection> sections = theSession.getUserInfo().getSections_publish();
    
    foldersForPagesToPublish = new HashMap<String, Folder>(); 
    pathsForPagesToPublish = new ArrayList<String>();
    
    resourcesToPublish = new HashMap<String, Resource>();
    pathsForResourcesToPublish = new ArrayList<String>();
    
    for(CMSSection s : sections)
    {
      try
      {         
        findPages(foldersForPagesToPublish, 
          pathsForPagesToPublish,
          resourcesToPublish,
          pathsForResourcesToPublish,
          s.getRootFolder(), s.getUrl());
      }
      catch(DatabaseConnectionException ex)
      {
        Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
        error("dberror");
      }
    }

    lsvPublishPages = new ListView("lsvPublishPages", pathsForPagesToPublish) {
    
      @Override
      protected void populateItem(ListItem item)
      {
        createPageEntries(item);
      }
    };
    
    add(lsvPublishPages);
    
    lsvPublishResources = new ListView("lsvPublishResources", pathsForResourcesToPublish) {

      @Override
      protected void populateItem(ListItem item)
      {
        createResourceEntries(item);
      }
    };
    
    add(lsvPublishResources);
    
    Label lblNoneResources = new Label("lblNoneResources", new Model(getString("none")));
    lblNoneResources.setVisible(resourcesToPublish.isEmpty());    
    add(lblNoneResources);
    
    Label lblNonePages = new Label("lblNonePages", new Model(getString("none")));
    lblNonePages.setVisible(foldersForPagesToPublish.isEmpty()); 
    add(lblNonePages);
    
  }
  
  private void createPageEntries(ListItem item)
  {
    String path = pathsForPagesToPublish.get(item.getIndex());
    final Folder folder = foldersForPagesToPublish.get(path);
    final Page page = folder.getPageWaitingForPublisher();

    item.add(new Label("lblPath", new Model(path)));
    item.add(new Label("lblSection", new Model(folder.getSection().getUrl())));
    item.add(new Label("lblEditor", new Model(page.getCreatedBy().getLoginName())));
    if(page.getCreatedTime() != null)
    {
      DateFormat d =DateFormat.getDateTimeInstance();
      item.add(new Label("lblTime", new Model(d.format(page.getCreatedTime()))));
    }
    else
    {
      item.add(new Label("lblTime", new Model(getString("notime"))));
    }

    item.add(new AjaxLink("lnkPreview") {

      @Override
      public void onClick(AjaxRequestTarget target)
      {
        if(folder != null && folder.getPageWaitingForPublisher() != null)
        {
          window.setPageCreator(new ModalWindow.PageCreator() {

            public org.apache.wicket.Page createPage()
            {
              try
              {
                return new PreviewPage(folder.getPageWaitingForPublisher().getContentAsXML());
              }
              catch (XSLTTransformFailedException ex)
              {
                Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
                return null;
              }
            }
          });
          window.setTitle(getString("preview") + ": " + 
            folder.getPageWaitingForPublisher().getTitle());
          window.show(target);
        }
        target.addComponent(feedback);
      }
    });

    item.add(new Link("lnkAccept") {

      @Override
      public void onClick()
      {
        publishPage(folder);
      }
    });

    item.add(new Link("lnkReject") {

      @Override
      public void onClick()
      {
        rejectPage(folder);
      }
    });

    item.add(new Link("lnkDiff") {
      @Override
      public void onClick()
      {
        showDiff(folder);
      }
    });
  }
  
  private void createResourceEntries(ListItem item)
  {
    String path = pathsForResourcesToPublish.get(item.getIndex());
    final Resource res = resourcesToPublish.get(path);
    
    item.add(new Label("lblPath", new Model(path)));
    item.add(new Label("lblType", new Model(res.getType())));
    item.add(new Label("lblEditor", new Model(res.getCreatedBy())));
    
    ResourceDownloadLink lnkShow = new ResourceDownloadLink("lnkShow", res);
    item.add(lnkShow);
    
    item.add(new Link("lnkAccept") {

      @Override
      public void onClick()
      {
        publishResource(res);
      }
    });
    
    item.add(new Link("lnkReject") {

      @Override
      public void onClick()
      {
        rejectResource(res);
      }
    });
    
  }
  
  private void publishPage(Folder folder)
  {
    Page oldPublished = folder.getPublishedPage();
    if(oldPublished != null)
    {
      if(folder.getHistory() == null)
      {
        folder.setHistory(new ArrayList<Page>());
      }
      folder.getHistory().add(folder.getPublishedPage());
    }
    folder.setPublishedPage(folder.getPageWaitingForPublisher());
    folder.getPublishedPage().setPublishedBy(theSession.getUserInfo());
    folder.getPublishedPage().setPublishedTime(new Date());
    folder.setPageWaitingForPublisher(null);
    try
    {
      folder = (Folder) ((GidooCMS) getApplication()).getDb().merge(folder);
    }
    catch(DatabaseConnectionException ex)
    {
      Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    setResponsePage(PublisherPage.class);
    
  }
  
  private void publishResource(Resource res)
  {
    res.setPublishedBy(theSession.getUserInfo());
    res.setIsPublished(true);
    try
    {
      res = (Resource) ((GidooCMS) getApplication()).getDb().merge(res);
    }
    catch(DatabaseConnectionException ex)
    {
      Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    setResponsePage(PublisherPage.class);
  }
  
  private void rejectPage(Folder folder)
  {
    if(folder.getHistory() == null)
    {
      folder.setHistory(new ArrayList<Page>());
    }
    folder.getHistory().add(folder.getPageWaitingForPublisher());
    folder.setPageWaitingForPublisher(null);
    
    
    try
    {
      folder = (Folder) ((GidooCMS) getApplication()).getDb().merge(folder);
    }
    catch(DatabaseConnectionException ex)
    {
      Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }

    setResponsePage(PublisherPage.class);
  }
  
  private void rejectResource(Resource res)
  {
    try
    {      
      File resFile = res.getFile((GidooCMS) getApplication());
      if(!resFile.delete())
      {
        warn(getString("filenotdeleted")  + " " + resFile.getAbsolutePath());
      }
      
      Folder f = res.getFolder();
      ((GidooCMS) getApplication()).getDb().remove(res);
      f.getResources().remove(res);
      ((GidooCMS) getApplication()).getDb().merge(f);
    }
    catch(DatabaseConnectionException ex)
    {
      Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    setResponsePage(PublisherPage.class);
  }
  
  private void showDiff(Folder folder)
  {
    Page old = folder.getPublishedPage();
    Page newer = folder.getPageWaitingForPublisher();
    
    String diff="";
    
    String titleOld="";
    
    if(old == null)
    {
      diff = XHTMLDiff.doDiff(getString("isnew"), newer.getContentAsXML());
    }
    else
    {
      diff = XHTMLDiff.doDiff(old.getContentAsXML(), newer.getContentAsXML());
      titleOld = old.getTitle();
    }
    
    diff = 
      "<p>" + getString("oldtitle") + titleOld + "<br />" +
      getString("newtitle") + newer.getTitle() + "</p>" +
      "<table style=\"text-align:left;width:100%\"><tr style=\"text-align:center\">" +
      "<th>" + getString("old") + "</th><th>" + getString("new") + "</th>" +
      diff + "</table>";
    
    MessageBox msgbox = new MessageBox(getString("difftitle"), diff, true, 
      MessageBox.MessageBoxButtons.OK, this, null);
    this.setResponsePage(msgbox);
  }
  
  private void findPages(
    HashMap<String, Folder> foldersToPublish, 
    List<String> pathsForFoldersToPublish, 
    HashMap<String, Resource> resourcesToPublish,
    List<String> pathsForResourcesToPublish,
    Folder folder, String path)
  {
    if(folder != null)
    {
      try
      {
        String folderName = folder.getName();
        
        if(folder.getPageWaitingForPublisher() != null)
        {
          foldersToPublish.put(path + "/" + folderName, folder);
          pathsForFoldersToPublish.add(path + "/" + folderName);
        }

        List<Resource> res = folder.getResources();
        if(res != null)
        {
          for(Resource r : res)
          {
            if(!r.getIsPublished())
            {
              if("".equals(folderName))
              {
                resourcesToPublish.put(path + "/" + r.getName(), r);
                pathsForResourcesToPublish.add(path +  "/" + r.getName());
              }
              else
              {
                resourcesToPublish.put(path + "/" + folderName + "/" + r.getName(), r);
                pathsForResourcesToPublish.add(path + "/" + folderName + "/" + r.getName());
              }
            }
          }
        }
        
        List<Folder> children = ((GidooCMS) getApplication()).getDb().getChildrenOfFolder(folder);
        if(children != null)
        {
          for(Folder f : children)
          {
            if("".equals(folderName))
            {
              findPages(foldersToPublish, 
                pathsForFoldersToPublish,
                resourcesToPublish,
                pathsForResourcesToPublish,
                f, path);              
            }
            else
            {
              findPages(foldersToPublish,
                pathsForFoldersToPublish,
                resourcesToPublish,
                pathsForResourcesToPublish,
                f, path + "/" + folderName);
            }
          }
        }
      }
      catch(DatabaseConnectionException ex)
      {
        Logger.getLogger(PublisherPage.class.getName()).log(Level.SEVERE, null, ex);
        error(getString("dberror"));
      }
    }
  }
  
}
